/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ucmconfchecker;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import org.apache.xmlbeans.XmlException;
import org.eclipse.emf.x2002.ecore.EStringToStringMapEntry;
import org.isistan.flabot.trace.logEcore.*;
import ucmconfchecker.pArchImpMapping.ArchImpMapping;
import ucmconfchecker.pArchitecture.Responsibility;
import ucmconfchecker.pExecutionTrace.ExecutionTrace;
import ucmconfchecker.pExecutionTrace.ImplEvent;
import ucmconfchecker.pImplementation.EClass;
import ucmconfchecker.pImplementation.EMethod;
import ucmconfchecker.pImplementation.EObject;
import ucmconfchecker.pImplementation.EThread;

/**
 *
 * @author Administrador
 */
public class TraceLogHandler{


    TraceLog traceLog;
    FlabotHandler flabot;
    Tag[] tags;
    
    public TraceLogHandler(String pathTraceLog, FlabotHandler flabot){
        TraceLogDocument traceDoc = null;
          try
          {
              traceDoc = TraceLogDocument.Factory.parse(new File(pathTraceLog));
          } catch (XmlException e)
          {
              e.printStackTrace();
          }catch (IOException e)
          {
              e.printStackTrace();
          }
          traceLog =traceDoc.getTraceLog();
          this.flabot = flabot;
          tags =traceLog.getTagsArray();
    }
    public ExecutionTrace getTrace(){

          LogContext[] contexts = traceLog.getContextsArray();
          String[] methodCalls = contexts[contexts.length-1].getTags2().split(" ");
          ExecutionTrace events = new ExecutionTrace();
          int methods = 0;
          for(int method =0; method < methodCalls.length;method++){
              
              //System.out.println("method: "+methodCalls[method]);
              ImplEvent event = getEvent(methodCalls[method]);
              System.out.println("Event:"+event);
              events.add(event);
              if(event.getEObject()!=null)
                methods ++;
          }
          System.out.println("Methods - trace: "+methods);
          return events;
    }
      public ArchImpMapping getAIMapping(){
          
          LogContext[] contexts = traceLog.getContextsArray();
          ArchImpMapping mapping = new ArchImpMapping();
          int methods=0;
          for(int context = 0; context <contexts.length-2;context++){
              if(contexts[context].getTags2()!=null){
                  String[] methodCalls = contexts[context].getTags2().split(" ");
                  ExecutionTrace events = new ExecutionTrace();
                  Responsibility responsibility =flabot.getResponsibility(contexts[context].getName());
                  System.out.println("Resposibility:"+responsibility.toString());
                  for(int method =0; method < methodCalls.length;method++){

                      //System.out.println("method: "+methodCalls[method]);
                      ImplEvent event = getEvent(methodCalls[method]);
                      System.out.println("--Event:"+event);
                      events.add(event);
                      if(event.getEObject()!=null)
                          methods ++;
                  }
                  System.out.println();
                  mapping.put(responsibility, events);
              }
          }
          return mapping;
    }

    Tag getContainedTag(String direction){
        String[] tree = direction.split("/");
        //empieza en 3: 2 por doble barra inicial(_\_\) + 1 por el tag 0
        Tag containedTag=tags[0];
        for(int treeLevel =3; treeLevel<tree.length;treeLevel++){
            String[] treeL = tree[treeLevel].substring(1).split("\\.");
            containedTag = containedTag.getContainedTagsArray(Integer.parseInt(treeL[1]));
        }//tenemos el containedTag
        return containedTag;
    }
    String getValue(EStringToTagMapEntry[] tags,String key){
      for(int i=0; i< tags.length;i++){
          if(tags[i].getKey().equals(key)){
              return tags[i].getValue2();
          }
      }return null;
    }
    String getValue(EStringToStringMapEntry[] tags,String key){
      for(int i=0; i< tags.length;i++){
          if(tags[i].getKey().equals(key)){
              return tags[i].getValue();
          }
      }return null;
    }
    
    public static String shortDirection(String direction){
        //acorta la direccion, reemplazando los nombres de nivel por ""
        String[] tree = direction.split("/");
        String result = "/";
        for(int treeLevel =2; treeLevel<tree.length;treeLevel++){
            String[] treeL = tree[treeLevel].substring(1).split("\\.");
            result += "/."+treeL[1];
        }//tenemos el containedTag
        return result;
    }public static String longDirection(String shortDirection){
        //recupera la direccion completa, reincertando los nombres de nivel
        String[] tree = shortDirection.split("/");
        String result = "/";
        for(int treeLevel =2; treeLevel<tree.length;treeLevel++){
            String[] treeL = tree[treeLevel].substring(1).split("\\.");
            if(treeLevel==2)result+="/tags";
            else result+="/containedTags";
            result += "."+treeL[1];
        }
        return result;
    }

    private String getSubDirection(String direction, int level) {
        //devuelve la direccion del nodo de nivel level, siendo 0 la raiz (tags)
        String[] tree = direction.split("/");
        String result = "/";
        for(int treeLevel =2; treeLevel<(level+2) && treeLevel<tree.length;treeLevel++){
            String[] treeL = tree[treeLevel].substring(1).split("\\.");
            if(treeLevel==2)result+="/tags";
            else result+="/containedTags";
            result += "."+treeL[1];
        }
        return result;
    }

    private ImplEvent getEvent(String direction) {
        Tag containedTag = getContainedTag(direction);
          //System.out.println("Class:"+containedTag.getContainedTagsArray(0));

          EStringToStringMapEntry[] propertiesMethod =containedTag.getPropertiesArray();
          Date timeStamp = new Date(Long.parseLong(propertiesMethod[2].getValue()));

          EStringToTagMapEntry[] methodTags =containedTag.getTagsArray();
          boolean found =false;
          String pathInstance= getValue(methodTags,"INSTANCE");

          EStringToStringMapEntry[] propertiesInstance =getContainedTag(pathInstance).getPropertiesArray();
          String sClass = null;
          String sObject = null;
          if(propertiesInstance[0].getValue().equals("false")){
              String[]instance= propertiesInstance[1].getValue().split("@");
              sClass  = instance[0];
              sObject = instance[1];
          }else{
              //metodo estatico (!)
          }
          String pathMethod= getValue(methodTags,"BEHAVIOR");
          String sMethod = null;
          if(pathMethod!=null)
            sMethod = getContainedTag(pathMethod).getPropertiesArray(0).getValue();
          
          String sThread = getContainedTag(getSubDirection(direction,3)).getPropertiesArray(0).getValue();
          ImplEvent implEvent = new ImplEvent(getEClass(sClass), getEMethod(sMethod), 
                               getEObject(sObject), getEThread(sThread), 
                               timeStamp);
          register(implEvent);
          return implEvent;
          
    }
    
    private HashMap<String,EClass> eClasses = new HashMap<String,EClass>();
    private HashMap<String,EMethod> eMethods = new HashMap<String,EMethod>();
    private HashMap<String,EObject> eObjects = new HashMap<String,EObject>();
    private HashMap<String,EThread> eThreads = new HashMap<String,EThread>();
    
    public EClass getEClass(String name){
        EClass eClass = eClasses.get(name);
        if(eClass==null){
            eClass = new EClass(name);
            eClasses.put(name,eClass);
        }
        return eClass;
    }
    public EMethod getEMethod(String name){
        EMethod eMethod = eMethods.get(name);
        if(eMethod==null){
            eMethod = new EMethod(name);
            eMethods.put(name,eMethod);
        }
        return eMethod;
    }
    public EObject getEObject(String name){
        EObject eObject = eObjects.get(name);
        if(eObject==null){
            eObject = new EObject(name);
            eObjects.put(name,eObject);
        }
        return eObject;
    }
    public EThread getEThread(String name){
        EThread eThread = eThreads.get(name);
        if(eThread==null){
            eThread = new EThread(name);
            eThreads.put(name,eThread);
        }
        return eThread;
    }

    private void register(ImplEvent implEvent) {
        implEvent.getEClass().addMethod(implEvent.getEMethod());
    }
    
    public Collection<EClass> getImplementation(){
        return eClasses.values();
    }
}
